package com.trial.area.trade.service;

import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import net.sf.json.JSONArray;
import net.sf.json.JSONObject;

import org.apache.commons.lang3.StringUtils;
import org.joda.time.DateTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.jfinal.weixin.sdk.api.PaymentApi;
import com.jfinal.weixin.sdk.kit.PaymentKit;
import com.trial.area.config.ConfigUtils;
import com.trial.area.coupon.dao.CouponDao;
import com.trial.area.coupon.entity.CouponVO;
import com.trial.area.goods.dao.GoodsDao;
import com.trial.area.goods.entity.GoodsVO;
import com.trial.area.trade.TradeUtils;
import com.trial.area.trade.controller.TradeH5Controller;
import com.trial.area.trade.dao.ChargeRecordDao;
import com.trial.area.trade.dao.TradeRecordDao;
import com.trial.area.trade.entity.ChargeRecordVO;
import com.trial.area.trade.entity.TradeRecordVO;
import com.trial.area.trade.param.TradeRecordParam;
import com.trial.area.weixin.common.WeixinUtils;

/**
 * 交易信息Service实现类
 *
 * @author 朱国军
 * @version 2016年07月17日 朱国军
 */
@Service
public class TradeRecordService {

	private Logger logger = LoggerFactory.getLogger(TradeH5Controller.class);

	@Autowired
	private TradeRecordDao tradeRecordDao;

	@Autowired
	private GoodsDao goodsDao;

	@Autowired
	private CouponDao couponDao;

	@Autowired
	private ChargeRecordDao chargeRecordDao;

	/**
	 * 根据ID获取交易信息实体
	 *
	 * @param id 主键
	 * @return 交易信息信息
	 */
	public TradeRecordVO findById(String id) {
		return tradeRecordDao.findById(id);
	}

	/**
	 * 按查询条件【分页】查询
	 *
	 * @param param 交易信息查询条件
	 * @return 交易信息列表
	 */
	public List<Map<String, Object>> queryByPage(TradeRecordParam param) {
		return tradeRecordDao.queryByPage(param);
	}

	/**
	 * 根据ID删除交易信息
	 *
	 * @param id 主键
	 */
	public Integer delete(String id) {
		return tradeRecordDao.delete(id);
	}

	/**
	 * 创建交易：1，校验券码，校验收货地址；2，调用统一下单接口
	 *
	 * @param tradeRecordVO 交易信息，包含goodsId,selectProperty,收货信息，couponId
	 * @return 创建成功
	 */
	@Transactional
	public Map<String, Object> createTrade(TradeRecordVO tradeRecordVO, String userId, String openId, String spbillCreateIp, String fullPath) {
		// 验证参数
		Map<String, Object> validResultMap = validTrade(tradeRecordVO);
		if (validResultMap != null) {
			return validResultMap;
		}

		Map<String, Object> resultMap = new HashMap<String, Object>();

		String goodsId = tradeRecordVO.getGoodsId();
		String couponId = tradeRecordVO.getCouponId();

		GoodsVO goodsVO = goodsDao.findById(goodsId);
		if (goodsVO == null) {
			resultMap.put("result", false);
			resultMap.put("message", "商品不存在");
			return resultMap;
		}

		CouponVO couponVO = couponDao.findById(couponId);

		if (couponVO == null || couponVO.getCouponState() != 2) {
			resultMap.put("result", false);
			resultMap.put("message", "券码不存在或失效");
			return resultMap;
		}

		if (couponVO == null || !StringUtils.equals(userId, couponVO.getUserId())) {
			resultMap.put("result", false);
			resultMap.put("message", "不能使用别人的券码");
			return resultMap;
		}

		// 支付金额=商品原始运费+券码加收邮费金额
		BigDecimal tradeAmount = goodsVO.getDeliveryFee();
		if (couponVO.getExtraFee() != null) {
			tradeAmount = tradeAmount.add(couponVO.getExtraFee());
		}
		// 支付金额 要加上偏远地区的加收邮费
		if (StringUtils.isNoneBlank(tradeRecordVO.getDeliveryProvince()) && StringUtils.contains(goodsVO.getRemoteArea(), tradeRecordVO.getDeliveryProvince())) {
			tradeAmount = tradeAmount.add(goodsVO.getExDeliveryFee());
		}

		// 创建订单
		tradeRecordVO.setCreateUser(userId);
		tradeRecordVO.setDataStatus(0);
		tradeRecordVO.setTradeAmount(tradeAmount);
		String tradeId = StringUtils.replace(UUID.randomUUID().toString(), "-", "");
		tradeRecordVO.setTradeId(tradeId);
		String tradeNo = TradeUtils.getTradeNo();
		tradeRecordVO.setTradeNo(tradeNo);
		tradeRecordVO.setTradeState(1);
		tradeRecordVO.setTradeTime(new Date(System.currentTimeMillis()));
		tradeRecordVO.setUserId(userId);
		tradeRecordDao.insert(tradeRecordVO);
		// 更新券码状态
		couponVO.setCouponState(3);
		couponDao.update(couponVO);

		// 创建支付信息
		ChargeRecordVO chargeRecordVO = new ChargeRecordVO();

		chargeRecordVO.setChargeAmount(tradeAmount);

		// 支付请求有效时间为24小时
		chargeRecordVO.setChargeEndTime(new Date(System.currentTimeMillis() + 86400000));
		chargeRecordVO.setChargeId(StringUtils.replace(UUID.randomUUID().toString(), "-", ""));
		chargeRecordVO.setChargeStartTime(new Date(System.currentTimeMillis()));
		chargeRecordVO.setChargeState(1);
		chargeRecordVO.setCreateUser(userId);
		chargeRecordVO.setDataStatus(0);
		chargeRecordVO.setOpenId(openId);
		chargeRecordVO.setSpbillCreateIp(spbillCreateIp);
		chargeRecordVO.setTradeId(tradeId);
		chargeRecordVO.setTradeNo(tradeNo);

		Map<String, String> orderMap = getOrderData(chargeRecordVO, goodsVO, tradeRecordVO, fullPath, tradeRecordVO.getSelectProperty());

		String orderXml = PaymentKit.toXml(orderMap);

		String resultXml = PaymentApi.pushOrder(orderMap);

		Map<String, String> orderResultMap = PaymentKit.xmlToMap(resultXml);

		if (StringUtils.equals("SUCCESS", orderResultMap.get("result_code"))) {
			chargeRecordVO.setChargeState(2);
			chargeRecordVO.setRequestParam(orderXml);
			chargeRecordVO.setResponseParam(resultXml);
			chargeRecordVO.setPrepayId(orderResultMap.get("prepay_id"));

			chargeRecordDao.insert(chargeRecordVO);

			resultMap.put("result", true);
			resultMap.put("message", "下单成功");
			resultMap.put("tradeId", tradeId);
			resultMap.put("chargeId", chargeRecordVO.getChargeId());

			return resultMap;
		} else {
			logger.error("下单失败，请求信息为：" + orderXml);
			logger.error("下单失败，返回信息为：" + resultXml);

			if (StringUtils.isNotBlank(orderResultMap.get("err_code_des"))) {
				throw new RuntimeException("下单失败,微信支付返回码为：" + orderResultMap.get("err_code") + "，返回信息为:" + orderResultMap.get("err_code_des"));
			} else {
				throw new RuntimeException("下单失败,微信支付返回码为：" + orderResultMap.get("return_code") + "，返回信息为:" + orderResultMap.get("return_msg"));
			}
		}
	}

	/**
	 * 生成订单数据
	 *
	 * @return
	 */
	private Map<String, String> getOrderData(ChargeRecordVO chargeRecordVO, GoodsVO goodsVO, TradeRecordVO tradeRecordVO, String fullPath, String selectProperty) {
		Map<String, String> orderMap = new HashMap<String, String>();

		// 公众账号ID appid 是 String(32) wxd678efh567hg6787 微信分配的公众账号ID（企业号corpid即为此appId）
		orderMap.put("appid", WeixinUtils.getApiConfig().getAppId());

		// 商户号 mch_id 是 String(32) 1230000109 微信支付分配的商户号
		orderMap.put("mch_id", ConfigUtils.getStringValueByKey("weixin_mch_id"));
		// 设备号 device_info 否 String(32) 013467007045764 终端设备号(门店号或收银设备ID)，注意：PC网页或公众号内支付请传"WEB"
		orderMap.put("device_info", "WEB");
		// 随机字符串 nonce_str 是 String(32) 5K8264ILTKCH16CQ2502SI8ZNMTM67VS 随机字符串，不长于32位。推荐随机数生成算法
		orderMap.put("nonce_str", StringUtils.replace(UUID.randomUUID().toString(), "-", ""));

		// 商品描述 body 是 String(128) 腾讯充值中心-QQ会员充值 商品简单描述，该字段须严格按照规范传递，具体请见参数规定

		orderMap.put("body", "试用区-" + goodsVO.getGoodsTypeName());

		// 商品详情 detail
		String goodsDetail = createGoodsDetail(goodsVO, selectProperty);
		orderMap.put("detail", goodsDetail);

		// 商户订单号 out_trade_no 是 String(32) 20150806125346 商户系统内部的订单号,32个字符内、可包含字母, 其他说明见商户订单号
		orderMap.put("out_trade_no", chargeRecordVO.getTradeNo());

		// 货币类型 fee_type 否 String(16) CNY 符合ISO 4217标准的三位字母代码，默认人民币：CNY，其他值列表详见货币类型
		orderMap.put("fee_type", "CNY");
		// 总金额 total_fee 是 Int 888 订单总金额，单位为分，详见支付金额
		Integer toyalFee = chargeRecordVO.getChargeAmount().multiply(new BigDecimal(100)).intValue();
		orderMap.put("total_fee", String.valueOf(toyalFee));

		// 终端IP spbill_create_ip 是 String(16) 123.12.12.123 APP和网页支付提交用户端ip，Native支付填调用微信支付API的机器IP。
		orderMap.put("spbill_create_ip", chargeRecordVO.getSpbillCreateIp());
		// 交易起始时间 time_start 否 String(14) 20091225091010 订单生成时间，格式为yyyyMMddHHmmss，如2009年12月25日9点10分10秒表示为20091225091010
		DateTime timeStart = new DateTime(chargeRecordVO.getChargeStartTime());
		orderMap.put("time_start", timeStart.toString("yyyyMMddHHmmss"));
		// 交易结束时间 time_expire 否 String(14) 20091227091010 订单失效时间，格式为yyyyMMddHHmmss，如2009年12月27日9点10分10秒表示为20091227091010
		DateTime timeExpire = new DateTime(chargeRecordVO.getChargeEndTime());
		orderMap.put("time_expire", timeExpire.toString("yyyyMMddHHmmss"));
		// 通知地址 notify_url 是 String(256) http://www.weixin.qq.com/wxpay/pay.php 接收微信支付异步通知回调地址，通知url必须为直接可访问的url，不能携带参数。
		orderMap.put("notify_url", fullPath + "/uncheck/pay/notify");
		// 交易类型 trade_type 是 String(16) JSAPI 取值如下：JSAPI，NATIVE，APP，详细说明见参数规定
		orderMap.put("trade_type", "JSAPI");
		// 用户标识 openid
		orderMap.put("openid", chargeRecordVO.getOpenId());

		// 签名 sign 是 String(32) C380BEC2BFD727A4B6845133519F3AD6 签名，详见签名生成算法
		String sign = PaymentKit.createSign(orderMap, ConfigUtils.getStringValueByKey("weixin_paterner_key"));
		orderMap.put("sign", sign);
		return orderMap;
	}

	private String createGoodsDetail(GoodsVO goodsVO, String selectProperty) {
		JSONObject goodsDetail = new JSONObject();
		JSONArray goodsArray = new JSONArray();
		JSONObject goods = new JSONObject();

		// goods_id String 必填 32 商品的编号
		goods.put("goods_id", goodsVO.getGoodsId());
		// goods_name String 必填 256 商品名称
		goods.put("goods_name", goodsVO.getGoodsName());
		// goods_num Int 必填 商品数量
		goods.put("goods_num", 1);
		// price Int 必填 商品单价，单位为分
		Integer price = goodsVO.getDeliveryFee().multiply(new BigDecimal(100)).intValue();
		goods.put("price", price);
		// body String 可选 1000 商品描述信息
		goods.put("body", goodsVO.getGoodsDetail() + "," + selectProperty);

		goodsArray.add(goods);

		goodsDetail.put("goods_detail", goodsArray);
		return goodsDetail.toString();
	}

	/**
	 * 校验券码，校验收货地址等信息
	 *
	 * @param tradeRecordVO
	 * @return
	 */
	private Map<String, Object> validTrade(TradeRecordVO tradeRecordVO) {
		Map<String, Object> resultMap = new HashMap<String, Object>();
		if (StringUtils.isBlank(tradeRecordVO.getGoodsId())) {
			resultMap.put("result", false);
			resultMap.put("message", "缺失商品ID");
			return resultMap;
		}

		if (StringUtils.isBlank(tradeRecordVO.getCouponId())) {
			resultMap.put("result", false);
			resultMap.put("message", "缺失券码ID");
			return resultMap;
		}

		if (StringUtils.isBlank(tradeRecordVO.getDeliveryAddress())) {
			resultMap.put("result", false);
			resultMap.put("message", "收货地址不能为空");
			return resultMap;
		}

		if (StringUtils.isBlank(tradeRecordVO.getDeliveryCity())) {
			resultMap.put("result", false);
			resultMap.put("message", "收货城市不能为空");
			return resultMap;
		}

		if (StringUtils.isBlank(tradeRecordVO.getDeliveryProvince())) {
			resultMap.put("result", false);
			resultMap.put("message", "收货省份不能为空");
			return resultMap;
		}

		if (StringUtils.isBlank(tradeRecordVO.getContactName())) {
			resultMap.put("result", false);
			resultMap.put("message", "联系人不能为空");
			return resultMap;
		}

		if (StringUtils.isBlank(tradeRecordVO.getContactPhone())) {
			resultMap.put("result", false);
			resultMap.put("message", "联系电话不能为空");
			return resultMap;
		}

		return null;
	}

	/**
	 * 审核支付成功未确认的订单
	 *
	 * @return 审核结果和审核时间
	 */
	public Map<String, Object> audit(TradeRecordParam tradeRecordParam) {
		Date nowTime = new Date(System.currentTimeMillis());
		tradeRecordParam.setAuditTime(nowTime);
		Integer auditNum = tradeRecordDao.audit(tradeRecordParam);

		String auditTimeStart = new DateTime(nowTime).minusSeconds(1).toString("yyyy-MM-dd HH:mm:ss");

		String auditTimeEnd = new DateTime(nowTime).plusSeconds(1).toString("yyyy-MM-dd HH:mm:ss");

		Map<String, Object> resultMap = new HashMap<String, Object>();

		resultMap.put("auditNum", auditNum);
		resultMap.put("tradeState", 4);
		resultMap.put("auditTimeStart", auditTimeStart);
		resultMap.put("auditTimeEnd", auditTimeEnd);
		resultMap.put("result", true);
		resultMap.put("message", "成功确认" + auditNum + "条订单");
		return resultMap;
	}

	/**
	 * 更新物流单号
	 *
	 * @param tradeList
	 * @return
	 */
	public String updateDeliveryNo(List<Map<String, String>> tradeList) {
		Integer updateNum = 0;
		String resultMsg = "";
		if (tradeList == null || tradeList.size() == 0) {
			return "未读取到物流数据";
		} else {
			for (Map<String, String> tradeMap : tradeList) {
				if (StringUtils.isNotBlank(tradeMap.get("tradeNo")) && StringUtils.isNotBlank(tradeMap.get("deliveryCompany"))
						&& StringUtils.isNotBlank(tradeMap.get("deliveryNo"))) {
					TradeRecordVO tradeRecordVO = new TradeRecordVO();
					tradeRecordVO.setTradeNo(tradeMap.get("tradeNo"));
					tradeRecordVO.setDeliveryCompany(tradeMap.get("deliveryCompany"));
					tradeRecordVO.setDeliveryNo(tradeMap.get("deliveryNo"));
					tradeRecordVO.setTradeState(5);
					Integer effetNum = tradeRecordDao.updateByTradeNo(tradeRecordVO);
					if (effetNum == 0) {
						resultMsg = resultMsg + ",未找到单号为" + tradeMap.get("tradeNo") + "的订单";
					} else {
						updateNum = updateNum + effetNum;
					}

				} else {
					resultMsg = resultMsg + ",单号" + tradeMap.get("tradeNo") + "的订单物流数据缺失";
				}
			}
		}
		resultMsg = resultMsg + ",成功更新" + updateNum + "条物流单号";
		return resultMsg;
	}

	/**
	 * 根据商品ID，状态，确认时间，分类查询订单
	 *
	 * @param tradeRecordParam
	 * @return
	 */
	public List<Map<String, Object>> queryByGoodsId(TradeRecordParam tradeRecordParam) {
		return tradeRecordDao.queryByGoodsId(tradeRecordParam);
	}

	/**
	 * 关闭订单
	 *
	 * @param tradeRecordVO 订单VO
	 * @return 成功关闭的数量
	 */
	@Transactional
	public Integer cancleTrade(TradeRecordVO tradeRecordVO) {
		Integer resultNum = 0;
		if (tradeRecordVO.getTradeState() == 1) {
			CouponVO couponVO = couponDao.findById(tradeRecordVO.getCouponId());

			tradeRecordVO.setTradeState(11);
			resultNum = tradeRecordDao.update(tradeRecordVO);

			couponVO.setCouponState(2);
			resultNum = couponDao.update(couponVO);
		}

		return resultNum;
	}

	/**
	 * 查询24小时内未支付的订单
	 */
	public List<TradeRecordVO> queryNoPayTrade() {
		return tradeRecordDao.queryNoPayTrade();
	}

	/**
	 * 更新物流单号
	 *
	 * @param tradeRecordVO
	 * @return
	 */
	public String updateDeliveryNo(TradeRecordVO tradeRecordVO) {
		Integer updateNum = 0;
		String resultMsg = "";
		
		if(tradeRecordVO==null){
			resultMsg = resultMsg + "订单物流数据缺失";
			return resultMsg;
		}
		
		if (tradeRecordVO.getTradeState() == 4) {
			tradeRecordVO.setTradeState(5);
		}
		
		if (StringUtils.isNotBlank(tradeRecordVO.getTradeNo()) && StringUtils.isNotBlank(tradeRecordVO.getDeliveryCompany())
				&& StringUtils.isNotBlank(tradeRecordVO.getDeliveryNo())) {
			Integer effetNum = tradeRecordDao.updateByTradeNo(tradeRecordVO);
			if (effetNum == 0) {
				resultMsg = resultMsg + ",未找到单号为" + tradeRecordVO.getTradeNo() + "的订单";
			} else {
				updateNum = updateNum + effetNum;
			}
		}else{
			resultMsg = resultMsg + ",单号" + tradeRecordVO.getTradeNo() + "的订单物流数据缺失";
		}

		resultMsg = resultMsg + ",成功更新" + updateNum + "条物流单号";
		return resultMsg;
	}
}
